﻿using System;
using System.Security.Cryptography;
using System.Text;

namespace Fuse8.DomainFramework.Common.Utilities
{
    /// <summary>
    /// 
    /// </summary>
    public static class HashUtility
    {
        private static Random _rand = new Random();

        /// <summary>
        /// Generates a cryptographically strong salt.
        /// </summary>
        /// <returns>
        /// </returns>
        public static string CreateSalt()
        {
            // Define min and max salt sizes.
            int minSaltSize = 4;
            int maxSaltSize = 8;

            // Generate a random number for the size of the salt.
            int saltSize = _rand.Next(minSaltSize, maxSaltSize);

            // Allocate a byte array, which will hold the salt.
            byte[] saltBytes = new byte[saltSize];

            // Initialize a random number generator.
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

            // Fill the salt with cryptographically strong byte values.
            rng.GetNonZeroBytes(saltBytes);

            return Convert.ToBase64String(saltBytes);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="password"></param>
        /// <returns></returns>
        public static string CreatePasswordHash(string password)
        {
            Guard.ArgumentNotEmpty(password, "password");
            
            // Convert plain text into a byte array.
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(password);

            byte[] computedHash;

            // Compute the salted hash.
            using (HashAlgorithm hash = new SHA256Managed())
            {
                computedHash = hash.ComputeHash(plainTextBytes);
            }

            return Convert.ToBase64String(computedHash);
        }

        /// <summary>
        /// Generates a cryptographically strong salt.
        /// </summary>
        /// <param name="password"></param>
        /// <param name="salt"></param>
        /// <returns></returns>
        public static string CreatePasswordHash(string password, string salt)
        {
            // Append salt to the password.
            string plainText = string.Concat(password, salt);

            return CreatePasswordHash(plainText);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="passwordHash"></param>
        /// <param name="evaluatedHash"></param>
        /// <returns></returns>
        public static bool ValidatePassword(string passwordHash, string evaluatedHash)
        {
            return passwordHash.Equals(evaluatedHash, StringComparison.Ordinal);
        }
    }
}
